home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_068 / mg1b / echo.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  11KB  |  527 lines

  1. /*
  2.  *        Echo line reading and writing.
  3.  *
  4.  * Common routines for reading
  5.  * and writing characters in the echo line area
  6.  * of the display screen. Used by the entire
  7.  * known universe.
  8.  */
  9. #include    "def.h"
  10. #ifdef    VARARGS
  11. #  include    <varargs.h>
  12.     static veread();
  13. VOID    ewprintf();
  14. #endif
  15. static VOID    eformat();
  16. static VOID    eputi();
  17. static VOID    eputl();
  18. static VOID    eputs();
  19. static VOID    eputc();
  20.  
  21. int    epresf    = FALSE;        /* Stuff in echo line flag.    */
  22. /*
  23.  * Erase the echo line.
  24.  */
  25. VOID
  26. eerase() {
  27.     ttcolor(CTEXT);
  28.     ttmove(nrow-1, 0);
  29.     tteeol();
  30.     ttflush();
  31.     epresf = FALSE;
  32. }
  33.  
  34. /*
  35.  * Ask "yes" or "no" question.
  36.  * Return ABORT if the user answers the question
  37.  * with the abort ("^G") character. Return FALSE
  38.  * for "no" and TRUE for "yes". No formatting
  39.  * services are available. No newline required.
  40.  */
  41. eyorn(sp) char *sp; {
  42.     register KEY    s;
  43.  
  44.     if (kbdmop == NULL) ewprintf("%s? (y or n) ", sp);
  45.     for (;;) {
  46.         s = getkey(0);
  47.         if (s == 'y' || s == 'Y') return (TRUE);
  48.         if (s == 'n' || s == 'N') return (FALSE);
  49.         if (s == (KCTRL|'G') || s == (KCTLX|KCTRL|'G')
  50.         ||  s == (KMETA|KCTRL|'G')) {
  51.             (VOID) ctrlg(FALSE, 1, KRANDOM);
  52.             return ABORT;
  53.         }
  54.         if (kbdmop == NULL)
  55.             ewprintf("Please answer y or n.  %s? (y or n) ", sp);
  56.     }
  57.     /*NOTREACHED*/
  58. }
  59.  
  60. /*
  61.  * Like eyorn, but for more important question. User must type either all of
  62.  * "yes" or "no", and the trainling newline.
  63.  */
  64. eyesno(sp) char *sp; {
  65.     register int    s;
  66.     char        buf[64];
  67.  
  68.     s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
  69.     for (;;) {
  70.         if (s == ABORT) return ABORT;
  71.         if (s != FALSE) {
  72.             if ((buf[0] == 'y' || buf[0] == 'Y')
  73.             &&  (buf[1] == 'e' || buf[1] == 'E')
  74.             &&  (buf[2] == 's' || buf[2] == 'S')) return TRUE;
  75.             if ((buf[0] == 'n' || buf[0] == 'N')
  76.             &&  (buf[1] == 'o' || buf[0] == 'O')) return FALSE;
  77.         }
  78.         s = ereply("Please answer yes or no.  %s? (yes or no) ",
  79.                buf, sizeof(buf), sp);
  80.     }
  81.     /*NOTREACHED*/
  82. }
  83. /*
  84.  * Write out a prompt, and read back a
  85.  * reply. The prompt is now written out with full "ewprintf"
  86.  * formatting, although the arguments are in a rather strange
  87.  * place. This is always a new message, there is no auto
  88.  * completion, and the return is echoed as such.
  89.  */
  90. #ifdef    VARARGS
  91. ereply(va_alist)
  92. va_dcl
  93. {
  94.     register int i;
  95.     va_list pvar;
  96.     register char *fp, *buf;
  97.     register int nbuf;
  98.     
  99.     va_start(pvar);
  100.     fp = va_arg(pvar, char *);
  101.     buf = va_arg(pvar, char *);
  102.     nbuf = va_arg(pvar, int);
  103.     i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar);
  104.     va_end(pvar);
  105.     return i;
  106. }
  107. #else
  108. /* VARARGS3 */
  109. ereply(fp, buf, nbuf, arg) char *fp, *buf; int nbuf; long arg; {
  110.     return (eread(fp, buf, nbuf, EFNEW|EFCR, (char *)&arg));
  111. }
  112. #endif
  113.  
  114. /*
  115.  * This is the general "read input from the
  116.  * echo line" routine. The basic idea is that the prompt
  117.  * string "prompt" is written to the echo line, and a one
  118.  * line reply is read back into the supplied "buf" (with
  119.  * maximum length "len"). The "flag" contains EFNEW (a
  120.  * new prompt), an EFFUNC (autocomplete), or EFCR (echo
  121.  * the carriage return as CR).
  122.  */
  123. /* VARARGS4 */
  124. #ifdef    VARARGS
  125. eread(va_alist)
  126. va_dcl
  127. {
  128.     va_list pvar;
  129.     char *fp, *buf;
  130.     int nbuf, flag, i;
  131.     va_start(pvar);
  132.     fp   = va_arg(pvar, char *);
  133.     buf  = va_arg(pvar, char *);
  134.     nbuf = va_arg(pvar, int);
  135.     flag = va_arg(pvar, int);
  136.     i = veread(fp, buf, nbuf, flag, &pvar);
  137.     va_end(pvar);
  138.     return i;
  139. }
  140. #endif
  141.  
  142. #ifdef    VARARGS
  143. static veread(fp, buf, nbuf, flag, ap) char *fp; char *buf; va_list *ap; {
  144. #else
  145. eread(fp, buf, nbuf, flag, ap) char *fp; char *buf; char *ap; {
  146. #endif
  147.     register int    cpos;
  148.     register int    i;
  149.     register KEY    c;
  150.  
  151.     cpos = 0;
  152.     if (kbdmop != NULL) {            /* In a macro.        */
  153.         while ((c = *kbdmop++) != '\0')
  154.             buf[cpos++] = (char) c;
  155.         buf[cpos] = '\0';
  156.         goto done;
  157.     }
  158.     if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
  159.         ttcolor(CTEXT);
  160.         ttmove(nrow-1, 0);
  161.         epresf = TRUE;
  162.     } else
  163.         eputc(' ');
  164.     eformat(fp, ap);
  165.     tteeol();
  166.     ttflush();
  167.     for (;;) {
  168.         c = getkey(KQUOTE|KNOMAC);
  169.         if ((flag&EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
  170.             cpos += complete(flag, c, buf, cpos);
  171.             continue;
  172.         }
  173.         switch (c) {
  174.         case 0x0A:
  175.         case 0x0D:            /* Return, done.    */
  176.             if ((flag&EFFUNC) != 0) {
  177.                 if ((i = complete(flag, c, buf, cpos)) == 0)
  178.                     continue;
  179.                 if (i > 0) cpos += i;
  180.             }
  181.             buf[cpos] = '\0';
  182.             if ((flag&EFCR) != 0) {
  183.                 ttputc(0x0D);
  184.                 ttflush();
  185.             }
  186.             if (kbdmip != NULL) {
  187.                 if (kbdmip+cpos+1 > &kbdm[NKBDM-3]) {
  188.                     ewprintf("Keyboard macro overflow");
  189.                     ttflush();
  190.                     return FALSE;
  191.                 }
  192.                 for (i = 0; i <= cpos; ++i)
  193.                     *kbdmip++ = (KEY) buf[i];
  194.             }
  195.             goto done;
  196.  
  197.         case CCHR('G'):            /* Bell, abort.        */
  198.             eputc(CCHR('G'));
  199.             (VOID) ctrlg(FALSE, 0, KRANDOM);
  200.             ttflush();
  201.             return (ABORT);
  202.  
  203.         case 0x7F:            /* Rubout, erase.    */
  204.             if (cpos != 0) {
  205.                 ttputc('\b');
  206.                 ttputc(' ');
  207.                 ttputc('\b');
  208.                 --ttcol;
  209.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  210.                     ttputc('\b');
  211.                     ttputc(' ');
  212.                     ttputc('\b');
  213.                     --ttcol;
  214.                 }
  215.                 ttflush();
  216.             }
  217.             break;
  218.  
  219.         case CCHR('X'):            /* C-X            */
  220.         case CCHR('U'):            /* C-U, kill line.    */
  221.             while (cpos != 0) {
  222.                 ttputc('\b');
  223.                 ttputc(' ');
  224.                 ttputc('\b');
  225.                 --ttcol;
  226.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  227.                     ttputc('\b');
  228.                     ttputc(' ');
  229.                     ttputc('\b');
  230.                     --ttcol;
  231.                 }
  232.             }
  233.             ttflush();
  234.             break;
  235.  
  236.         case CCHR('Q'):            /* C-Q, quote next    */
  237.             c = getkey(KQUOTE|KNOMAC) ;
  238.         default:            /* All the rest.    */
  239.             if (cpos < nbuf-1) {
  240.                 buf[cpos++] = (char) c;
  241.                 eputc((char) c);
  242.                 ttflush();
  243.             }
  244.         }
  245.     }
  246. done:
  247.     if (buf[0] == '\0')
  248.         return (FALSE);
  249.     return (TRUE);
  250. }
  251.  
  252. /*
  253.  * do completion on a list of objects.
  254.  */
  255. complete(flags, c, buf, cpos) register char *buf; register int cpos; {
  256.     register LIST    *lh, *lh2;
  257.     int        i, nxtra;
  258.     int        nhits, bxtra;
  259.     int        wflag = FALSE;
  260.     int        msglen, nshown;
  261.     char        *msg;
  262.  
  263.     if ((flags&EFFUNC) != 0) lh = &(symbol[0]->s_list);
  264.     else if ((flags&EFBUF) != 0) lh = &(bheadp->b_list);
  265.     else panic("broken complete call: flags");
  266.  
  267.     if (c == ' ') wflag = TRUE;
  268.     else if (c != '\t' && c != 0x0D && c != 0x0A)
  269.         panic("broken complete call: c");
  270.  
  271.     nhits = 0;
  272.     nxtra = HUGE;
  273.  
  274.     while (lh != NULL) {
  275.         for (i=0; i<cpos; ++i) {
  276.             if (buf[i] != lh->l_name[i])
  277.                 break;
  278.         }
  279.         if (i == cpos) {
  280.             if (nhits == 0)
  281.                 lh2 = lh;
  282.             ++nhits;
  283.             if (lh->l_name[i] == '\0') nxtra = -1;
  284.             else {
  285.                 bxtra = getxtra(lh, lh2, cpos, wflag);
  286.                 if (bxtra < nxtra) nxtra = bxtra;
  287.                 lh2 = lh;
  288.             }
  289.         }
  290.         lh = lh->l_next;
  291.     }
  292.     if (nhits == 0)
  293.         msg = " [No match]";
  294.     else if (nhits > 1 && nxtra == 0)
  295.         msg = " [Ambiguous]";
  296.     else {        /* Got a match, do it to it */
  297.         /*
  298.          * Being lazy - ought to check length, but all things
  299.          * autocompleted have known types/lengths.
  300.          */ 
  301.         if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1;
  302.         for (i = 0; i < nxtra; ++i) {
  303.             buf[cpos] = lh2->l_name[cpos];
  304.             eputc(buf[cpos++]);
  305.         }
  306.         ttflush();
  307.         if (nxtra < 0 && c != 0x0D && c != 0x0A) return 0;
  308.         return nxtra;
  309.     }
  310.         /* Set up backspaces, etc., being mindful of echo line limit */
  311.     msglen = strlen(msg);
  312.     nshown = (ttcol + msglen + 2 > ncol) ? 
  313.             ncol - ttcol - 2 : msglen;
  314.     eputs(msg);
  315.     ttcol -= (i = nshown);        /* update ttcol!        */
  316.     while (i--)            /* move back before msg        */
  317.         ttputc('\b');
  318.     ttflush();            /* display to user        */
  319.     i = nshown;
  320.     while (i--)            /* blank out    on next flush    */
  321.         eputc(' ');
  322.     ttcol -= (i = nshown);        /* update ttcol on BS's        */
  323.     while (i--)
  324.         ttputc('\b');        /* update ttcol again!        */
  325.     return 0;
  326.  
  327. }
  328.  
  329. /*
  330.  * The "lp1" and "lp2" point to list structures. The
  331.  * "cpos" is a horizontal position in the name.
  332.  * Return the longest block of characters that can be
  333.  * autocompleted at this point. Sometimes the two
  334.  * symbols are the same, but this is normal.
  335.   */
  336. getxtra(lp1, lp2, cpos, wflag) register LIST *lp1, *lp2; register int wflag; {
  337.     register int    i;
  338.  
  339.     i = cpos;
  340.     for (;;) {
  341.         if (lp1->l_name[i] != lp2->l_name[i]) break;
  342.         if (lp1->l_name[i] == '\0') break;
  343.         ++i;
  344.         if (wflag && !ISWORD(lp1->l_name[i-1])) break;
  345.     }
  346.     return (i - cpos);
  347. }
  348.  
  349. /*
  350.  * Special "printf" for the echo line.
  351.  * Each call to "ewprintf" starts a new line in the
  352.  * echo area, and ends with an erase to end of the
  353.  * echo line. The formatting is done by a call
  354.  * to the standard formatting routine.
  355.  */
  356. #ifdef    VARARGS
  357. VOID
  358. ewprintf(va_alist)
  359. va_dcl
  360. {
  361.     va_list pvar;
  362.     register char *fp;
  363.  
  364.     va_start(pvar);
  365.     fp = va_arg(pvar, char *);
  366. #else
  367. /* VARARGS1 */
  368. ewprintf(fp, arg) char *fp; {
  369. #endif
  370.     ttcolor(CTEXT);
  371.     ttmove(nrow-1, 0);
  372. #ifdef    VARARGS
  373.     eformat(fp, &pvar);
  374.     va_end(pvar);
  375. #else
  376.     eformat(fp, (char *)&arg);
  377. #endif
  378.     tteeol();
  379.     ttflush();
  380.     epresf = TRUE;
  381. }
  382.  
  383. /*
  384.  * Printf style formatting. This is
  385.  * called by both "ewprintf" and "ereply" to provide
  386.  * formatting services to their clients. The move to the
  387.  * start of the echo line, and the erase to the end of
  388.  * the echo line, is done by the caller.
  389.  * Note: %c works, and prints the "name" of the key. However
  390.  * the key must be cast to an int to avoid tripping over
  391.  * various oddities in C argument passing.
  392.  */
  393. static VOID
  394. eformat(fp, ap) register char *fp;
  395. #ifdef VARARGS
  396. register va_list *ap;
  397. #else
  398. register char *ap;
  399. #endif
  400. {
  401.     register int    c;
  402.     char        kname[NKNAME];
  403.  
  404.     while ((c = *fp++) != '\0') {
  405.         if (c != '%')
  406.             eputc(c);
  407.         else {
  408.             c = *fp++;
  409.             switch (c) {
  410.             case 'c':
  411. #ifdef    VARARGS
  412.                 keyname(kname, va_arg(*ap, int));
  413. #else
  414.                 /*NOSTRICT*/
  415.                 keyname(kname, *(int *)ap);
  416.                 ap += sizeof(int);
  417. #endif
  418.                 eputs(kname);
  419.                 break;
  420.  
  421.             case 'd':
  422. #ifdef    VARARGS
  423.                 eputi(va_arg(*ap, int), 10);
  424. #else
  425.                 /*NOSTRICT*/
  426.                 eputi(*(int *)ap, 10);
  427.                 ap += sizeof(int);
  428. #endif
  429.                 break;
  430.  
  431.             case 'o':
  432. #ifdef    VARARGS
  433.                 eputi(va_arg(*ap, int), 8);
  434. #else
  435.                 /*NOSTRICT*/
  436.                 eputi(*(int *)ap,  8);
  437.                 ap += sizeof(int);
  438. #endif
  439.                 break;
  440.  
  441.             case 's':
  442. #ifdef    VARARGS
  443.                 eputs(va_arg(*ap, char *));
  444. #else
  445.                 /*NOSTRICT*/
  446.                 eputs(*(char **)ap);
  447.                 ap += sizeof(char *);
  448. #endif
  449.                 break;
  450.             case 'l':/* explicit longword */
  451.                 c = *fp++;
  452.                 switch(c) {
  453.                 case 'd':
  454. #ifdef    VARARGS
  455.                     eputl((long)va_arg(*ap, long), 10L);
  456. #else
  457.                     /*NOSTRICT*/
  458.                     eputl(*(long *)ap, 10L);
  459.                     ap += sizeof(long);
  460. #endif
  461.                     break;
  462.                 default:
  463.                     eputc(c);
  464.                     break;
  465.                 }
  466.                 break;
  467.  
  468.             default:
  469.                 eputc(c);
  470.             }
  471.         }
  472.     }
  473. }
  474.  
  475. /*
  476.  * Put integer, in radix "r".
  477.  */
  478. static VOID
  479. eputi(i, r) register int i; register int r; {
  480.     register int    q;
  481.  
  482.     if ((q=i/r) != 0)
  483.         eputi(q, r);
  484.     eputc(i%r+'0');
  485. }
  486.  
  487. /*
  488.  * Put long, in radix "r".
  489.  */
  490. static VOID
  491. eputl(l, r) register long l; register long r; {
  492.     register long    q;
  493.  
  494.     if ((q=l/r) != 0)
  495.         eputl(q, r);
  496.     eputc((int)(l%r)+'0');
  497. }
  498.  
  499. /*
  500.  * Put string.
  501.  */
  502. static VOID
  503. eputs(s) register char *s; {
  504.     register int    c;
  505.  
  506.     while ((c = *s++) != '\0')
  507.         eputc(c);
  508. }
  509.  
  510. /*
  511.  * Put character. Watch for
  512.  * control characters, and for the line
  513.  * getting too long.
  514.  */
  515. static VOID
  516. eputc(c) register char c; {
  517.     if (ttcol+2 < ncol) {
  518.         if (ISCTRL(c) != FALSE) {
  519.             eputc('^');
  520.             c ^= 0x40;
  521.         }
  522.         ttputc(c);
  523.         ++ttcol;
  524.     }
  525. }
  526.  
  527.